package org.wattdepot.gdata.kukuicup.updater.energylasttwentyfourhours;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.gdata.kukuicup.service.GDataBatchRequest;
import org.wattdepot.gdata.kukuicup.service.GDataService;
import org.wattdepot.gdata.kukuicup.service.WattDepotService;
import org.wattdepot.gdata.kukuicup.updater.BaselineView;
import org.wattdepot.gdata.kukuicup.updater.GDataCronTask;
import org.wattdepot.util.tstamp.Tstamp;
import it.sauronsoftware.cron4j.TaskExecutionContext;

/**
 * Gets the energy used by a source for each hour of the last twenty four hours. 
 * @author Philip Johnson
 */
public class EnergyLastTwentyFourHoursTask extends GDataCronTask {
  
  /** Holds the read-only view of the baseline data. */
  private BaselineView baselineView;
  
  /**
   * Creates the task that gets woken up every hour to get the last 24 hours of energy. 
   * @param wattDepotService The WattDepot service configuration data. 
   * @param gdataService The gdata service configuration data.
   * @param spreadsheetURL The URL to the spreadsheet containing the data.
   * @param sourceName The WattDepot source of interest.
   * @param isVirtual True if the source is virtual.
   * @param row The row in the spreadsheet that this source's data appears in.
   */
  public EnergyLastTwentyFourHoursTask(WattDepotService wattDepotService, GDataService gdataService,
      URL spreadsheetURL, String sourceName, boolean isVirtual, int row) {
    super(wattDepotService, gdataService, spreadsheetURL, sourceName, row, 
        "EnergyLastTwentyFourHours", isVirtual);
    baselineView = new BaselineView(gdataService);
  }

  /**
   * The method called once an hour to update the last twenty four hour spreadsheet.
   * @param context Ignored.
   * @throws RuntimeException If problems occur (which they shouldn't). 
   */
  @Override
  public void execute(TaskExecutionContext context) throws RuntimeException {
    // Need to deal with missing data, like when sensors are not working. 
    System.out.format("Running EnergyLastTwentyFourHours for source %s%n", sourceName);

    // Get the current time. 
    XMLGregorianCalendar currTime = Tstamp.makeTimestamp();

    // Get the hourly energy values for the past 24 hours.
    startWattDepotTiming();
    List<String> energies = getHourlyEnergy(currTime);
    stopWattDepotTiming();

    startGDataTiming();

    // Get the baseline data. 
    // THis doesn't work right any longer since getHourlyBaselines must be passed the startDay,
    // not the startHour.  If this code gets used in future, fix it. 
    int startHour = currTime.getHour();
    List<Integer> baselines = baselineView.getHourlyBaselines(sourceName, startHour);
    
    // Add the actual data to the spreadsheet.
    GDataBatchRequest request = new GDataBatchRequest(gdataService, spreadsheetURL);
    try {
      // Add the last update field
      request.addRequest(this.row, 2, gdataService.makeLastUpdate(currTime));
      // Add the actual energy data. 
      for (int i = 0; i < 24; i++) {
        request.addRequest(this.row, i + 3, energies.get(i)); 
      }
      int column = 27;
      for (Integer baseline : baselines) {
        request.addRequest(this.row, column, String.valueOf(baseline));
        column++;
      }
      // Send the request.
      request.sendRequest();
    }
    catch (Exception e) {
      System.out.println("Error making batch request for source " + this.sourceName);
      e.printStackTrace();
    }
    stopGDataTiming();
    printTaskResults("Last 24", "kWh", "OK");
  }
  
  /**
   * Returns a list with the 24 hours of hourly energy prior to the passed timestamp.  
   * @param currTime The time that we go backward from. 
   * @return A list of 24 integers containing hourly energy for a 24 hour period. 
   */
  private List<String> getHourlyEnergy(XMLGregorianCalendar currTime) {
    WattDepotClient client = this.wattDepotService.getClient();
    List<String> energies = new ArrayList<String>();
    // Make a new timestamp for the previous day with mins, secs, and millisecs set to zero.
    XMLGregorianCalendar startHour = Tstamp.incrementDays(currTime, -1);
    startHour.setMinute(0);
    startHour.setSecond(0);
    startHour.setMillisecond(0);
    // Now gather the energy data from the past 24 hours and add to spreadsheet.
    for (int i = 0; i < 24; i++) {
      XMLGregorianCalendar begin = Tstamp.incrementHours(startHour, i);
      XMLGregorianCalendar end = Tstamp.incrementHours(startHour, i + 1);
      Integer energy = 0;
      try {
        energy = (int) client.getEnergyConsumed(sourceName, begin, end, 10);
      }
      catch (Exception e) {
        System.out.format("Failed to get energy for %s for hour %s, %s%n", sourceName, begin, 
            e.getMessage());
      }
      energies.add(String.valueOf(energy));
    }
    return energies;
  }

}
